#pragma once
#include <future>
#include <functional>
#include <memory>
#include <mutex>
#include <future>
#include <unordered_map>
#include "../common/net.hpp"
#include "../common/message.hpp"

namespace rpc
{
    namespace client
    {
        class Requestor
        {
        public:
            using ptr = std::shared_ptr<Requestor>;
            using RequestCallback = std::function<void(const BaseMessage::ptr &)>;
            using AsyncResponse = std::future<BaseMessage::ptr>;
            //请求描述
            struct RequestDescribe
            {
                using ptr = std::shared_ptr<RequestDescribe>;
                BaseMessage::ptr request;//请求信息
                RType rtype;//请求类型
                std::promise<BaseMessage::ptr> response;//异步请求设置
                RequestCallback callback;//回调函数类型设置
            };

            //注册给dispatcher
            void onResponse(const BaseConnection::ptr &conn, BaseMessage::ptr &msg)//BaseMessage通用于Rcp,Topic,Server
            {
                std::string rid = msg->rid();//获取rid
                RequestDescribe::ptr rdp = getDescribe(rid);//查找请求描述
                if (rdp.get() == nullptr)
                {
                    LOG(ERROR, "收到响应 - %s,但是未找到对应的请求描述", rid.c_str());
                    return;
                }
                if (rdp->rtype == RType::REQ_ASYNC)//异步
                {
                    rdp->response.set_value(msg);//把结果设置到promise里面
                }
                else if (rdp->rtype == RType::REQ_CALLBACK)
                {
                    if (rdp->callback) //回调类型
                        rdp->callback(msg);
                }
                else
                {
                    LOG(ERROR, "请求类型未知");
                }
                delDescribe(rid);//处理响应结束,删除掉这个响应
            }

            //发送请求
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, AsyncResponse &async_rsp)//异步:连接+请求+类型
            {
                RequestDescribe::ptr rdp = newDescribe(req, RType::REQ_ASYNC);
                if (rdp.get() == nullptr)
                {
                    LOG(ERROR, "构造请求描述对象失败");
                    return false;
                }
                conn->send(req);
                async_rsp = rdp->response.get_future();
                return true;
            }

            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, BaseMessage::ptr &rsp)
            {
                AsyncResponse rsp_future;
                bool ret = send(conn, req, rsp_future);
                if (ret == false)
                {
                    return false;
                }
                rsp = rsp_future.get();
                return true;
            }

            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, const RequestCallback &cb)//回调处理的方式->直接调用回调函数
            {
                RequestDescribe::ptr rdp = newDescribe(req, RType::REQ_CALLBACK, cb);
                if (rdp.get() == nullptr)
                {
                    LOG(ERROR,"构造请求描述对象失败！");
                    return false;
                }
                conn->send(req);
                return true;
            }

        private:

            //创建一个请求
            RequestDescribe::ptr newDescribe(const BaseMessage::ptr &req, RType rtype, const RequestCallback &cb = RequestCallback())
            {
                std::unique_lock<std::mutex> lock(_mutex);
                RequestDescribe::ptr rd = std::make_shared<RequestDescribe>();
                rd->request = req;
                rd->rtype = rtype;
                if (rtype == RType::REQ_CALLBACK && cb)
                {
                    rd->callback = cb;
                }
                _request_desc.insert(std::make_pair(req->rid(), rd));
                return rd;
            }

            //获取请求的请求描述
            RequestDescribe::ptr getDescribe(const std::string &rid)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _request_desc.find(rid);
                if (it == _request_desc.end())
                {
                    return RequestDescribe::ptr();
                }
                return it->second;
            }

            //删除rid的请求
            void delDescribe(const std::string &rid)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _request_desc.erase(rid);
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, RequestDescribe::ptr> _request_desc;//请求描述
        };
    }
}


